﻿#include "MaterialGraphNodeView.h"

#include "Framework/Editor.h"

#include "MaterialGraph/Pin/MaterialGraphPinView.h"
#include "MaterialGraph/Pin/MaterialGraphPinViewModel.h"

#include "MaterialGraphNodeViewModel.h"

#include "Widgets/TextWidget.h"
#include "Widgets/RectangleWidget.h"
#include "Widgets/Mouse/MouseWidget.h"
#include "Widgets/ImageWidget.h"
#include "Widgets/EditorDragableSpinWidget.h"
#include "Widgets/EditorCheckBoxWidget.h"
#include "Widgets/EditableTextWidget.h" 

#include "Framework/Editor.h"
#include "Theme/EditorTheme.h"

#include "Asset/EditorDefaultPackage.h"
#include "MaterialGraph/MaterialGraphView.h"
#include "Window/EditorWindowGroupViewModel.h"

void RMaterialGraphNodeView::BindViewModel(TSharedObjectPtr<RMaterialGraphNodeViewModel> InModel)
{
    BaseViewModel=InModel;

    for(int64_t i=0;i<BaseViewModel->GetInputNum();i++)
    {
        TSharedObjectPtr<RMaterialGraphPinViewModel> Pin=BaseViewModel->GetInput(i);
        CClass* ViewClass=REditor::Get()->GetViewClass(Pin->GetClass());
        TSharedObjectPtr<RMaterialGraphPinView> InputPinView=NewObject<RMaterialGraphPinView>(ViewClass,this);
        InputPinView->BindViewModel(Pin);
        InputPinViews.Add(InputPinView);
    }
   
    for(int64_t i=0;i<BaseViewModel->GetOutputNum();i++)
    {
        TSharedObjectPtr<RMaterialGraphPinViewModel> OutputPin=BaseViewModel->GetOutput(i);
        CClass* ViewClass=REditor::Get()->GetViewClass(OutputPin->GetClass());
        TSharedObjectPtr<RMaterialGraphPinView> OutputPinView=NewObject<RMaterialGraphPinView>(ViewClass,this);
        OutputPinView->BindViewModel(OutputPin);
        OutputPinViews.Add(OutputPinView);
    }
}

void RMaterialGraphNodeView::CreateWidget(TSharedObjectPtr<RWidget> InParentWidget)
{
    auto Node=CreateNodeWidget(InParentWidget);
    RootWidget=NewWidget<RWidget>(Node);
    RootWidget->Anchor.Fill(Node);

    RegenerateContentWidget();    

    BaseViewModel->OnNodeLineChanged.Bind([this](){
        
        RootWidget->ClearSubWidgets();
        RegenerateContentWidget();
    });
    
}

void RMaterialGraphNodeView::FillContextMenu(TVector<SEditorContextMenuLine> &InOutMenuLines)
{
    //增加参数相关内容
    if(BaseViewModel->PotentiallyIsOrIsParameter())
    {
        auto& ConvertParameterLine= InOutMenuLines.Emplace();
        if(BaseViewModel->IsParameter())
        {
            ConvertParameterLine.Text=U"设为常量";
        }
        else
        {
            ConvertParameterLine.Text=U"设为参数";
        }
        ConvertParameterLine.OnClicked.Bind([this](){
            BaseViewModel->ToggleParameter();
        });
    }

    auto& DeleteLine= InOutMenuLines.Emplace();
    DeleteLine.Text=U"删除";
    DeleteLine.OnClicked.Bind([this](){
        GetGraphView()->DeleteSelectedNode();
    });
    DeleteLine.ShorcutText=U"Delete";
}

TSharedObjectPtr<RMaterialGraphView> RMaterialGraphNodeView::GetGraphView()
{
    return GetOwner();
}

TSharedObjectPtr<RWidget> RMaterialGraphNodeView::CreateNodeWidget(TSharedObjectPtr<RWidget> InParentWidget)
{
    auto Root=NewWidget<RWidget>(InParentWidget);
    Root->Width=[this](){
        return BaseViewModel->GetNodeWidth();
    };
    Root->Height=[this](){
        return BaseViewModel->GetNodeHeight();
    };
    
    Root->Anchor.LeftReference=InParentWidget;
    Root->Anchor.LeftReferenceEdge=EHorizontalWidgetEdge::Center;
    Root->Anchor.LeftOffset=[this](){
        return BaseViewModel->GetNodeWidgetSpaceX();
    };
    Root->Anchor.TopReference=InParentWidget;
    Root->Anchor.TopReferenceEdge=EVerticalWidgetEdge::Center;
    Root->Anchor.TopOffset=[this](){
        return BaseViewModel->GetNodeWidgetSpaceY();
    };
    Root->Scale=[this](){
        return SVec2(BaseViewModel->GetScale(),BaseViewModel->GetScale());
    };

    const float BackgroundBorderSize=1;
    auto Background=NewWidget<RRectangleWidget>(Root);
    Background->FillColor= BaseViewModel->BackgroundColor;
    Background->Anchor.Fill(Root);
    Background->Radius= BaseViewModel->BackgroundRadius;
    Background->BorderSize=BackgroundBorderSize;
    Background->BorderColor=[this](){
        if(BaseViewModel->IsSelected())
        {
            return SColor::FromHexRGB(0xE3E4E4);
        }
        return SColor::FromHexRGB(0x101010);
    };

    auto DragNodeMouse=NewWidget<RMouseWidget>(Root);
    RMouseWidgetWeakPtr WeakDragNodeMouse=DragNodeMouse;
    DragNodeMouse->Anchor.Fill(Root);
    DragNodeMouse->Drag->bIsEnabled=true;
    static SVec2 NodeOffsetOnDragStart;
    DragNodeMouse->Drag->OnDragStarted.Bind([this,WeakDragNodeMouse](){
        NodeOffsetOnDragStart.X=BaseViewModel->GetNodeX();
        NodeOffsetOnDragStart.Y=BaseViewModel->GetNodeY();
    });
    DragNodeMouse->Drag->OnDragMoved.Bind([this,WeakDragNodeMouse](const SVec2& TotalMove){
        auto NewPos=NodeOffsetOnDragStart+TotalMove/ BaseViewModel->GetScale();
        BaseViewModel->SetNodePosition(NewPos);
    });    
    DragNodeMouse->OnClicked.BindLambda([this](const SMouseButtonEvent& Event){
        BaseViewModel->SelectThisNode();
        if(Event.Button==EMouseButton::Right)
        {
            //弹出菜单  
            TVector<SEditorContextMenuLine> RootContextMenu;
            FillContextMenu(RootContextMenu);
            REditorWindowGroupViewModel::Get()->ShowContextMenu(
                RootContextMenu
                ,SMouseButtonEvent::GetMosuePositionOnScreen()
                ,200
            );
            
        }
        return true;
    });

    auto TitleBackground=NewWidget<RRectangleWidget>(Root);
    TitleBackground->FillColor=[this](){
        return BaseViewModel->GetTitleBackgroundColor();
    };
    TitleBackground->Y=TitleBackground;
    TitleBackground->Height= BaseViewModel->LineHeight-2;
    TitleBackground->Radius=BaseViewModel->BackgroundRadius-TitleBackground;
    TitleBackground->Anchor.LeftReference=Root;
    TitleBackground->Anchor.LeftOffset=TitleBackground;
    TitleBackground->Anchor.RightReference=Root;
    TitleBackground->Anchor.RightOffset=TitleBackground;

    
    auto TitleBackground2=NewWidget<RRectangleWidget>(TitleBackground);
    TitleBackground2->FillColor= TitleBackground->FillColor;

    TitleBackground2->Height=[this](){
        if(BaseViewModel->IsParameter())
        {
            //参数节点的标题占据两行
            return BaseViewModel->LineHeight *1.5 ;
        }
        //普通节点的标题占据一行
        return BaseViewModel->LineHeight *0.5;
    };

    TitleBackground2->Y= BaseViewModel->LineHeight *0.5;
    TitleBackground2->Anchor.HorizontalFill(TitleBackground);

    if(BaseViewModel->PotentiallyIsOrIsParameter())
    {
        //参数节点的标题占据两行
        //第一行是参数名
        //第二行是节点名

        auto ParameterNameLine=NewWidget<REditableTextWidget>(Root);
        ParameterNameLine->Text=[this](){
            return BaseViewModel->GetParameterName();
        };
        ParameterNameLine->VerticalAlignment=ETextVerticalAlignment::Center;
        ParameterNameLine->Anchor.VerticalFill(TitleBackground);
        ParameterNameLine->X= BaseViewModel->LineHorizontalPadding;
        ParameterNameLine->Anchor.RightReference=Root;
        ParameterNameLine->Anchor.RightOffset= BaseViewModel->LineHorizontalPadding;
        ParameterNameLine->Visible=[this](){
            return BaseViewModel->IsParameter();
        };

        ParameterNameLine->OnTextAccepted.BindLambda([this](const CString& NewName){
            BaseViewModel->SetParameterName(NewName);
        });
    }

    auto NodeNameLine=NewWidget<RTextWidget>(Root);
    NodeNameLine->Text=BaseViewModel->GetName();
    NodeNameLine->VerticalAlignment=ETextVerticalAlignment::Center;
        
    NodeNameLine->Height= BaseViewModel->LineHeight;
    NodeNameLine->Anchor.BottomReference=TitleBackground2;
        
    NodeNameLine->X= BaseViewModel->LineHorizontalPadding;
    NodeNameLine->Anchor.RightReference=Root;
    NodeNameLine->Anchor.RightOffset= BaseViewModel->LineHorizontalPadding;

    return Root;
}

TSharedObjectPtr<RWidget> RMaterialGraphNodeView::CreateSimpleOutputPinWidget(
    TSharedObjectPtr<RWidget> InNodeWidget
    , TSharedObjectPtr<RWidget> InParentWidget
    , int64_t InOutputPinIndex
    , int64_t InLineIndex)
{
    auto OutputLine=CreateLine(InNodeWidget,InParentWidget,InLineIndex);

    auto OutputNameWidget=NewWidget<RTextWidget>(OutputLine);
    OutputNameWidget->Text=BaseViewModel->GetOutputPinName(InOutputPinIndex);
    OutputNameWidget->VerticalAlignment=ETextVerticalAlignment::Center;
    OutputNameWidget->Anchor.VerticalFill(OutputLine);
    OutputNameWidget->HorizontalAlignment=ETextHorizontalAlignment::Right;
    OutputNameWidget->Anchor.RightReference=InNodeWidget;
    OutputNameWidget->Anchor.RightOffset=BaseViewModel->LineHorizontalPadding;
    OutputNameWidget->Anchor.LeftReference=InNodeWidget;
    OutputNameWidget->Anchor.LeftOffset=BaseViewModel->LineHorizontalPadding;
    
    auto OutputPinView=OutputPinViews[InOutputPinIndex];
    OutputPinView->CreateWidget(InNodeWidget,OutputLine);

    return OutputLine;
}

TSharedObjectPtr<RWidget> RMaterialGraphNodeView::CreateSimpleInputPinWidget(
    TSharedObjectPtr<RWidget> InNodeWidget
    , TSharedObjectPtr<RWidget> InParentWidget
    , int64_t InOutputPinIndex
    , int64_t InLineIndex)
{
    auto InputLine=CreateLine(InNodeWidget,InParentWidget,InLineIndex);

    auto InputNameWidget=NewWidget<RTextWidget>(InputLine);
    InputNameWidget->Text=BaseViewModel->GetInputPinName(InOutputPinIndex);
    InputNameWidget->VerticalAlignment=ETextVerticalAlignment::Center;
    InputNameWidget->Anchor.VerticalFill(InputLine);
    InputNameWidget->HorizontalAlignment=ETextHorizontalAlignment::Left;
    InputNameWidget->Anchor.LeftReference=InNodeWidget;
    InputNameWidget->Anchor.LeftOffset=BaseViewModel->LineHorizontalPadding;
    InputNameWidget->Anchor.RightReference=InNodeWidget;
    InputNameWidget->Anchor.RightOffset=BaseViewModel->LineHorizontalPadding;
    
    auto InputPinView=InputPinViews[InOutputPinIndex];
    InputPinView->CreateWidget(InNodeWidget,InputLine);

    return InputLine;
}

TSharedObjectPtr<RWidget> RMaterialGraphNodeView::CreateLine(
    TSharedObjectPtr<RWidget> InNodeWidget
    , TSharedObjectPtr<RWidget> InParentWidget
    , int64_t InLineIndex
    ,int64_t InLineNum
    )
{
    auto Line=NewWidget<RWidget>(InParentWidget);
    Line->Anchor.HorizontalFill(InNodeWidget);
    Line->Height= BaseViewModel->LineHeight * InLineNum;
    Line->Anchor.TopReference=InNodeWidget;
    Line->Anchor.TopOffset= BaseViewModel->GetLineY(InLineIndex);

    return Line;
}

TSharedObjectPtr<RWidget> RMaterialGraphNodeView::CreateVector1DInputPinWidgetWithoutLimit(
    TSharedObjectPtr<RWidget> InNodeWidget
    , TSharedObjectPtr<RWidget> InParentWidget
    , int64_t InInputPinIndex
    , int64_t InLineIndex)
{
    auto ValueLine=CreateLine(InNodeWidget,InParentWidget,InLineIndex);

    //create pin
    InputPinViews[InInputPinIndex]->CreateWidget(InNodeWidget,ValueLine);


    auto ValueLineBackground= NewWidget<RRectangleWidget>(ValueLine);
    RRectangleWidgetWeakPtr WeakValueLineBackground=ValueLineBackground;
    ValueLineBackground->Anchor.VerticalFill(ValueLine);
    ValueLineBackground->Anchor.LeftReference=ValueLine;
    ValueLineBackground->Anchor.LeftOffset=BaseViewModel->LineHorizontalPadding;
    ValueLineBackground->Anchor.RightReference=ValueLine;
    ValueLineBackground->Anchor.RightOffset=BaseViewModel->LineHorizontalPadding;

    ValueLineBackground->Radius=BaseViewModel->BackgroundRadius;

    auto ValueTextHighlight=NewWidget<RRectangleWidget>(ValueLineBackground);
    
    const float ButtonWidth=BaseViewModel->LineHeight*0.5;

    auto PinNameWidget=NewWidget<RTextWidget>(ValueLineBackground);
    PinNameWidget->X=5;
    PinNameWidget->Text=[this,InInputPinIndex](){
        return BaseViewModel->GetInputPinName(InInputPinIndex);
    };
    PinNameWidget->VerticalAlignment=ETextVerticalAlignment::Center;
    PinNameWidget->Anchor.VerticalFill(ValueTextHighlight);
    PinNameWidget->Anchor.RightReference=ValueTextHighlight;
    PinNameWidget->Anchor.RightOffset=5;
    PinNameWidget->Anchor.LeftReference=ValueTextHighlight;


    auto ValueText=NewWidget<REditorDragableSpinWidget>(ValueLineBackground);
    REditorDragableSpinWidgetWeakPtr WeakValueText=ValueText;
    ValueText->Anchor.VerticalFill(ValueLineBackground);
    ValueText->Anchor.LeftReference=ValueLineBackground;
    ValueText->Anchor.LeftOffset=[this,ButtonWidth,WeakValueText](){
        if(WeakValueText->IsEditing())
        {
            return 0.0f;
        }
        else
        {
            return ButtonWidth;
        }
    };
    ValueText->Anchor.RightReference=ValueLineBackground;
    ValueText->Anchor.RightOffset=[this,ButtonWidth,WeakValueText](){
        if(WeakValueText->IsEditing())
        {
            return 0.0f;
        }
        else
        {
            return ButtonWidth;
        }
    };

    ValueText->HorizontalAlignment=
        [this,WeakValueText]()
        {
            if(WeakValueText->IsEditing())
            {
                return ETextHorizontalAlignment::Left;
            }
            return ETextHorizontalAlignment::Right;
        };
    ValueText->VerticalAlignment=ETextVerticalAlignment::Center;
    ValueText->Value= [this,InInputPinIndex](){
        return BaseViewModel->GetInputDefaultX(InInputPinIndex);
    };

    ValueText->OnAccepted.BindLambda([this,InInputPinIndex](ETextEditStopReason Reason,float NewValue ){
        if(Reason==ETextEditStopReason::Cancel)
        {
            return;
        }
        BaseViewModel->SetInputDefaultX(InInputPinIndex,NewValue);
    });

    PinNameWidget->Visible=[this,WeakValueText](){
        return !WeakValueText->IsEditing();
    };
    ValueLineBackground->FillColor=[this,WeakValueText](){
        if(WeakValueText->IsEditing())
        {
            return SColor::FromHexRGB(0x222222);
        }
        return SColor::FromHexRGB(0x545454);
    };
    
    auto DecreseButton=NewWidget<RMouseWidget>(ValueLineBackground);
    RMouseWidgetWeakPtr WeakDecreseButton=DecreseButton;
    DecreseButton->Anchor.VerticalFill(ValueLineBackground);
    DecreseButton->Width= ButtonWidth;
    DecreseButton->OnClicked.BindLambda([this,InInputPinIndex](const SMouseButtonEvent&){
        BaseViewModel->SetInputDefaultX(InInputPinIndex
            ,BaseViewModel->GetInputDefaultX(InInputPinIndex)-0.1);
        return true;
    });


    auto  DecreseButtonHighlight=NewWidget<RRectangleWidget>(DecreseButton);
    DecreseButtonHighlight->FillColor= SColor::FromHexRGB(0x797979);
    DecreseButtonHighlight->Anchor.Fill(DecreseButton);
    DecreseButtonHighlight->Visible=[this,WeakDecreseButton,WeakValueText](){
        return WeakDecreseButton->IsHovered()
        && !WeakValueText->IsEditing();
    };
    DecreseButtonHighlight->Radius=BaseViewModel->BackgroundRadius;

    auto DecreseButtonHighlight2=NewWidget<RRectangleWidget>(DecreseButton);
    DecreseButtonHighlight2->FillColor= SColor::FromHexRGB(0x797979);
    DecreseButtonHighlight2->Anchor.LeftReference=DecreseButtonHighlight;
    DecreseButtonHighlight2->Anchor.LeftReferenceEdge=EHorizontalWidgetEdge::Center;
    DecreseButtonHighlight2->Anchor.RightReference=DecreseButtonHighlight;
    DecreseButtonHighlight2->Anchor.VerticalFill(DecreseButtonHighlight);
    DecreseButtonHighlight2->Visible=[this,WeakDecreseButton,WeakValueText](){
        return WeakDecreseButton->IsHovered()
        && !WeakValueText->IsEditing();
    };


    auto DecreseButtonIcon=NewWidget<RImageWidget>(DecreseButton);
    DecreseButtonIcon->Anchor.Fill(DecreseButton);
    DecreseButtonIcon->Image= REditorDefaultPackage::Get()->GetIcon(U"CodiconChevronLeft");
    
    auto IncreaseButton=NewWidget<RMouseWidget>(ValueLineBackground);
    RMouseWidgetWeakPtr WeakIncreaseButton=IncreaseButton;
    IncreaseButton->Anchor.VerticalFill(ValueLineBackground);
    IncreaseButton->Width= ButtonWidth;
    IncreaseButton->Anchor.RightReference=ValueLineBackground;
    IncreaseButton->OnClicked.BindLambda([this,InInputPinIndex](const SMouseButtonEvent&){
        BaseViewModel->SetInputDefaultX(InInputPinIndex
            ,BaseViewModel->GetInputDefaultX(InInputPinIndex)+0.1);
        return true;
    });

    auto IncreaseButtonHighlight=NewWidget<RRectangleWidget>(IncreaseButton);
    IncreaseButtonHighlight->FillColor= SColor::FromHexRGB(0x797979);
    IncreaseButtonHighlight->Anchor.Fill(IncreaseButton);
    IncreaseButtonHighlight->Visible=[this,WeakIncreaseButton,WeakValueText](){
        return WeakIncreaseButton->IsHovered()
        && !WeakValueText->IsEditing();
    };
    IncreaseButtonHighlight->Radius=BaseViewModel->BackgroundRadius;

    auto IncreaseButtonHighlight2=NewWidget<RRectangleWidget>(IncreaseButton);
    IncreaseButtonHighlight2->FillColor= SColor::FromHexRGB(0x797979);
    IncreaseButtonHighlight2->Anchor.RightReference=IncreaseButtonHighlight;
    IncreaseButtonHighlight2->Anchor.RightReferenceEdge=EHorizontalWidgetEdge::Center;
    IncreaseButtonHighlight2->Anchor.LeftReference=IncreaseButtonHighlight;
    IncreaseButtonHighlight2->Anchor.VerticalFill(IncreaseButtonHighlight);
    IncreaseButtonHighlight2->Visible=[this,WeakIncreaseButton,WeakValueText](){
        return WeakIncreaseButton->IsHovered()
        && !WeakValueText->IsEditing();
    };

    auto IncreaseButtonIcon=NewWidget<RImageWidget>(IncreaseButton);
    IncreaseButtonIcon->Anchor.Fill(IncreaseButton);
    IncreaseButtonIcon->Image= REditorDefaultPackage::Get()->GetIcon(U"CodiconChevronRight");
    
    DecreseButtonIcon->Visible=[this,WeakDecreseButton,WeakIncreaseButton,WeakValueText](){
        return 
        (WeakValueText->IsHovered() || WeakDecreseButton->IsHovered() || WeakIncreaseButton->IsHovered())
        && !WeakValueText->IsEditing();
    };

    IncreaseButtonIcon->Visible=[this,WeakDecreseButton,WeakIncreaseButton,WeakValueText](){
        return 
        (WeakValueText->IsHovered() || WeakDecreseButton->IsHovered() || WeakIncreaseButton->IsHovered())
        && !WeakValueText->IsEditing();
    };

    
    ValueTextHighlight->FillColor= SColor::FromHexRGB(0x797979);
    ValueTextHighlight->Anchor.VerticalFill(ValueLine);
    ValueTextHighlight->Anchor.LeftReference=ValueText;
    ValueTextHighlight->Anchor.LeftOffset= 0;
    ValueTextHighlight->Anchor.RightReference=ValueText;
    ValueTextHighlight->Anchor.RightOffset=0;
    ValueTextHighlight->Visible=[this,WeakValueText,WeakIncreaseButton,WeakDecreseButton](){
        return WeakValueText->IsHovered()
        && !WeakValueText->IsEditing()
        && !WeakIncreaseButton->IsHovered()
        && !WeakDecreseButton->IsHovered(); 
    };

    return ValueLine;
}

TSharedObjectPtr<RWidget> RMaterialGraphNodeView::CreateVector1DInputPinWidgetWithLimit(
    TSharedObjectPtr<RWidget> InNodeWidget
    , TSharedObjectPtr<RWidget> InParentWidget
    , int64_t InInputPinIndex
    , int64_t InLineIndex
    , float InMinValue
    , float InMaxValue)
{
    auto ValueLine=CreateLine(InNodeWidget,InParentWidget,InLineIndex);

    //create pin
    InputPinViews[InInputPinIndex]->CreateWidget(InNodeWidget,ValueLine);

    auto Background= NewWidget<RRectangleWidget>(ValueLine);
    Background->Anchor.VerticalFill(ValueLine);
    Background->Anchor.LeftReference=ValueLine;
    Background->Anchor.LeftOffset=BaseViewModel->LineHorizontalPadding;
    Background->Anchor.RightReference=ValueLine;
    Background->Anchor.RightOffset=BaseViewModel->LineHorizontalPadding;
    Background->Radius=BaseViewModel->BackgroundRadius;

    auto NumberText=NewWidget<REditorDragableSpinWidget>(Background);
    REditorDragableSpinWidgetWeakPtr WeakNumberText=NumberText;
    NumberText->Anchor.Fill(Background);
    NumberText->HorizontalAlignment=[this,WeakNumberText](){
        if(WeakNumberText->IsEditing())
        {
            return ETextHorizontalAlignment::Left;
        }
        return ETextHorizontalAlignment::Right;
    };
    NumberText->Value= [this,InInputPinIndex](){
        return BaseViewModel->GetInputDefaultX(InInputPinIndex);
    };
    NumberText->OnAccepted.BindLambda([this,InInputPinIndex](ETextEditStopReason Reason,float NewValue ){
        if(Reason==ETextEditStopReason::Cancel)
        {
            return;
        }
        BaseViewModel->SetInputDefaultX(InInputPinIndex,NewValue);
    });

    NumberText->Step=0.1f;
    NumberText->MinValue=InMinValue;
    NumberText->MaxValue=InMaxValue;

    Background->FillColor=[this,WeakNumberText](){
        if(WeakNumberText->IsEditing())
        {
            return SColor::FromHexRGB(0x222222);
        }

        if(WeakNumberText->IsHovered())
        {
            return SColor::FromHexRGB(0x797979);
        }

        return SColor::FromHexRGB(0x545454);
    };

    auto PinNameWidget=NewWidget<RTextWidget>(Background);
    PinNameWidget->Anchor.VerticalFill(Background);
    PinNameWidget->Anchor.LeftReference=Background;
    PinNameWidget->Anchor.LeftOffset=5;
    PinNameWidget->Anchor.RightReference=Background;
    PinNameWidget->Text=[this,InInputPinIndex](){
        return BaseViewModel->GetInputPinName(InInputPinIndex);
    };
    PinNameWidget->VerticalAlignment=ETextVerticalAlignment::Center;

    return ValueLine;
}

TSharedObjectPtr<RWidget> RMaterialGraphNodeView::CreateVector1DWidgetWithoutLimit(
    TSharedObjectPtr<RWidget> InNodeWidget
    , TSharedObjectPtr<RWidget> InParentWidget
    , int64_t InLineIndex
    , TDelegate<float> InGetValue
    , TDelegate<void, float> InOnValueChanged
    )
{
    auto ValueLine=CreateLine(InNodeWidget,InParentWidget,InLineIndex);

    auto ValueLineBackground= NewWidget<RRectangleWidget>(ValueLine);
    ValueLineBackground->Anchor.VerticalFill(ValueLine);
    ValueLineBackground->Anchor.LeftReference=ValueLine;
    ValueLineBackground->Anchor.LeftOffset=BaseViewModel->LineHorizontalPadding;
    ValueLineBackground->Anchor.RightReference=ValueLine;
    ValueLineBackground->Anchor.RightOffset=BaseViewModel->LineHorizontalPadding;

    ValueLineBackground->Radius=BaseViewModel->BackgroundRadius;

    auto ValueTextHighlight=NewWidget<RRectangleWidget>(ValueLineBackground);
    auto ValueText=NewWidget<REditorDragableSpinWidget>(ValueLineBackground);
    REditorDragableSpinWidgetWeakPtr WeakValueText=ValueText;
    ValueText->Anchor.Fill(ValueLineBackground);
    ValueText->HorizontalAlignment=
        [this,WeakValueText]()
        {
            if(WeakValueText->IsEditing())
            {
                return ETextHorizontalAlignment::Left;
            }
            return ETextHorizontalAlignment::Center;
        };
    ValueText->VerticalAlignment=ETextVerticalAlignment::Center;
    ValueText->Value= [this,InGetValue](){
        return InGetValue.Execute();
    };

    ValueText->OnAccepted.BindLambda([this,InGetValue,InOnValueChanged](ETextEditStopReason Reason,float NewValue ){
        if(Reason==ETextEditStopReason::Cancel)
        {
            NewValue=InGetValue.Execute();
            return;
        }

        InOnValueChanged.Execute(NewValue);
    });

    ValueLineBackground->FillColor=[this,WeakValueText](){
        if(WeakValueText->IsEditing())
        {
            return SColor::FromHexRGB(0x222222);
        }
        return SColor::FromHexRGB(0x545454);
    };
    
    auto DecreseButton=NewWidget<RMouseWidget>(ValueLineBackground);
    RMouseWidgetWeakPtr WeakDecreseButton=DecreseButton;
    DecreseButton->Anchor.VerticalFill(ValueLineBackground);
    DecreseButton->Width= BaseViewModel->LineHeight*0.5;
    DecreseButton->OnClicked.BindLambda([this,InGetValue,InOnValueChanged](const SMouseButtonEvent&){
        float CurrentValue=InGetValue.Execute();
        InOnValueChanged.Execute(CurrentValue-0.1);
        return true;
    });


    auto  DecreseButtonHighlight=NewWidget<RRectangleWidget>(DecreseButton);
    DecreseButtonHighlight->FillColor= SColor::FromHexRGB(0x797979);
    DecreseButtonHighlight->Anchor.Fill(DecreseButton);
    DecreseButtonHighlight->Visible=[this,WeakDecreseButton,WeakValueText](){
        return WeakDecreseButton->IsHovered()
        && !WeakValueText->IsEditing();
    };
    DecreseButtonHighlight->Radius=BaseViewModel->BackgroundRadius;

    auto DecreseButtonHighlight2=NewWidget<RRectangleWidget>(DecreseButton);
    DecreseButtonHighlight2->FillColor= SColor::FromHexRGB(0x797979);
    DecreseButtonHighlight2->Anchor.LeftReference=DecreseButtonHighlight;
    DecreseButtonHighlight2->Anchor.LeftReferenceEdge=EHorizontalWidgetEdge::Center;
    DecreseButtonHighlight2->Anchor.RightReference=DecreseButtonHighlight;
    DecreseButtonHighlight2->Anchor.VerticalFill(DecreseButtonHighlight);
    DecreseButtonHighlight2->Visible=[this,WeakDecreseButton,WeakValueText](){
        return WeakDecreseButton->IsHovered()
        && !WeakValueText->IsEditing();
    };


    auto DecreseButtonIcon=NewWidget<RImageWidget>(DecreseButton);
    DecreseButtonIcon->Anchor.Fill(DecreseButton);
    DecreseButtonIcon->Image= REditorDefaultPackage::Get()->GetIcon(U"CodiconChevronLeft");
    DecreseButtonIcon->Visible=[this,WeakDecreseButton,WeakValueText](){
        return WeakValueText->IsHovered()
        && !WeakValueText->IsEditing();
    };

    auto IncreaseButton=NewWidget<RMouseWidget>(ValueLineBackground);
    RMouseWidgetWeakPtr WeakIncreaseButton=IncreaseButton;
    IncreaseButton->Anchor.VerticalFill(ValueLineBackground);
    IncreaseButton->Width= BaseViewModel->LineHeight*0.5;
    IncreaseButton->Anchor.RightReference=ValueLineBackground;
    IncreaseButton->OnClicked.BindLambda([this,InGetValue,InOnValueChanged](const SMouseButtonEvent&){
        float CurrentValue=InGetValue.Execute();
        InOnValueChanged.Execute(CurrentValue+0.1);
        return true;
    });

    auto IncreaseButtonHighlight=NewWidget<RRectangleWidget>(IncreaseButton);
    IncreaseButtonHighlight->FillColor= SColor::FromHexRGB(0x797979);
    IncreaseButtonHighlight->Anchor.Fill(IncreaseButton);
    IncreaseButtonHighlight->Visible=[this,WeakIncreaseButton,WeakValueText](){
        return WeakIncreaseButton->IsHovered()
        && !WeakValueText->IsEditing();
    };
    IncreaseButtonHighlight->Radius=BaseViewModel->BackgroundRadius;

    auto IncreaseButtonHighlight2=NewWidget<RRectangleWidget>(IncreaseButton);
    IncreaseButtonHighlight2->FillColor= SColor::FromHexRGB(0x797979);
    IncreaseButtonHighlight2->Anchor.RightReference=IncreaseButtonHighlight;
    IncreaseButtonHighlight2->Anchor.RightReferenceEdge=EHorizontalWidgetEdge::Center;
    IncreaseButtonHighlight2->Anchor.LeftReference=IncreaseButtonHighlight;
    IncreaseButtonHighlight2->Anchor.VerticalFill(IncreaseButtonHighlight);
    IncreaseButtonHighlight2->Visible=[this,WeakIncreaseButton,WeakValueText](){
        return WeakIncreaseButton->IsHovered()
        && !WeakValueText->IsEditing();
    };

    auto IncreaseButtonIcon=NewWidget<RImageWidget>(IncreaseButton);
    IncreaseButtonIcon->Anchor.Fill(IncreaseButton);
    IncreaseButtonIcon->Image= REditorDefaultPackage::Get()->GetIcon(U"CodiconChevronRight");
    IncreaseButtonIcon->Visible=[this,WeakIncreaseButton,WeakValueText](){
        return WeakValueText->IsHovered()
        && !WeakValueText->IsEditing();
    };

    
    ValueTextHighlight->FillColor= SColor::FromHexRGB(0x797979);
    ValueTextHighlight->Anchor.VerticalFill(ValueLine);
    ValueTextHighlight->Anchor.LeftReference=ValueText;
    ValueTextHighlight->Anchor.LeftOffset= BaseViewModel->LineHeight*0.5;
    ValueTextHighlight->Anchor.RightReference=ValueText;
    ValueTextHighlight->Anchor.RightOffset=BaseViewModel->LineHeight*0.5;
    ValueTextHighlight->Visible=[this,WeakValueText,WeakIncreaseButton,WeakDecreseButton](){
        return WeakValueText->IsHovered()
        && !WeakValueText->IsEditing()
        && !WeakIncreaseButton->IsHovered()
        && !WeakDecreseButton->IsHovered(); 
    };

    return ValueLine;
}

TSharedObjectPtr<RWidget> RMaterialGraphNodeView::CreateVector2DInputPinWidget(TSharedObjectPtr<RWidget> InNodeWidget, TSharedObjectPtr<RWidget> InParentWidget, int64_t InInputPinIndex, int64_t InLineIndex)
{
    auto AllLine=CreateLine(InNodeWidget,InParentWidget,InLineIndex,3);

    auto PinLine=CreateLine(InNodeWidget,AllLine,InLineIndex);
    {
        //create pin
        InputPinViews[InInputPinIndex]->CreateWidget(InNodeWidget,PinLine);

        auto PinNameWidget=NewWidget<RTextWidget>(PinLine);
        PinNameWidget->Text=[this,InInputPinIndex](){
            return BaseViewModel->GetInputPinName(InInputPinIndex);
        };
        PinNameWidget->VerticalAlignment=ETextVerticalAlignment::Center;
        PinNameWidget->Anchor.VerticalFill(PinLine);
        PinNameWidget->Anchor.LeftReference=PinLine;
        PinNameWidget->Anchor.LeftOffset=BaseViewModel->LineHorizontalPadding;
    }

    auto XYLines=CreateLine(InNodeWidget,AllLine,InLineIndex+1,2);
    XYLines->Visible=[this,InInputPinIndex](){
        return !InputPinViews[InInputPinIndex]->HasValidLink();
    };
  
    auto XLine= CreateVector1DWidgetWithoutLimit(
        InNodeWidget
        ,XYLines
        ,InLineIndex+1
        ,[this,InInputPinIndex](){
            return BaseViewModel->GetInputDefaultX(InInputPinIndex);
        }
        ,[this,InInputPinIndex](float NewValue){
            BaseViewModel->SetInputDefaultX(InInputPinIndex,NewValue);
        });

    auto YLine= CreateVector1DWidgetWithoutLimit(
        InNodeWidget
        ,XYLines
        ,InLineIndex+2
        ,[this,InInputPinIndex](){
            return BaseViewModel->GetInputDefaultY(InInputPinIndex);
        }
        ,[this,InInputPinIndex](float NewValue){
            BaseViewModel->SetInputDefaultY(InInputPinIndex,NewValue);
        });

    return AllLine;
}

TSharedObjectPtr<RWidget> RMaterialGraphNodeView::CreateVector3DInputPinWidget(TSharedObjectPtr<RWidget> InNodeWidget, TSharedObjectPtr<RWidget> InParentWidget, int64_t InInputPinIndex, int64_t InLineIndex)
{
    auto AllLine=CreateLine(InNodeWidget,InParentWidget,InLineIndex,4);

    auto PinLine=CreateLine(InNodeWidget,AllLine,InLineIndex);
    {
        //create pin
        InputPinViews[InInputPinIndex]->CreateWidget(InNodeWidget,PinLine);

        auto PinNameWidget=NewWidget<RTextWidget>(PinLine);
        PinNameWidget->Text=[this,InInputPinIndex](){
            return BaseViewModel->GetInputPinName(InInputPinIndex);
        };
        PinNameWidget->VerticalAlignment=ETextVerticalAlignment::Center;
        PinNameWidget->Anchor.VerticalFill(PinLine);
        PinNameWidget->Anchor.LeftReference=PinLine;
        PinNameWidget->Anchor.LeftOffset=BaseViewModel->LineHorizontalPadding;
    }

    auto XYZLines=CreateLine(InNodeWidget,AllLine,InLineIndex+1,3);
    XYZLines->Visible=[this,InInputPinIndex](){
        return !InputPinViews[InInputPinIndex]->HasValidLink();
    };

    auto XLine= CreateVector1DWidgetWithoutLimit(
        InNodeWidget
        ,XYZLines
        ,InLineIndex+1
        ,[this,InInputPinIndex](){
            return BaseViewModel->GetInputDefaultX(InInputPinIndex);
        }
        ,[this,InInputPinIndex](float NewValue){
            BaseViewModel->SetInputDefaultX(InInputPinIndex,NewValue);
        });

    auto YLine= CreateVector1DWidgetWithoutLimit(
        InNodeWidget
        ,XYZLines
        ,InLineIndex+2
        ,[this,InInputPinIndex](){
            return BaseViewModel->GetInputDefaultY(InInputPinIndex);
        }
        ,[this,InInputPinIndex](float NewValue){
            BaseViewModel->SetInputDefaultY(InInputPinIndex,NewValue);
        });

    auto ZLine= CreateVector1DWidgetWithoutLimit(
        InNodeWidget
        ,XYZLines
        ,InLineIndex+3
        ,[this,InInputPinIndex](){
            return BaseViewModel->GetInputDefaultZ(InInputPinIndex);
        }
        ,[this,InInputPinIndex](float NewValue){
            BaseViewModel->SetInputDefaultZ(InInputPinIndex,NewValue);
        });
    
    return AllLine;
}

TSharedObjectPtr<RWidget> RMaterialGraphNodeView::CreateColorInputPinWidget(
    TSharedObjectPtr<RWidget> InNodeWidget
    , TSharedObjectPtr<RWidget> InParentWidget
    , int64_t InInputPinIndex
    , int64_t InLineIndex)
{
    auto ValueLine=CreateLine(InNodeWidget,InParentWidget,InLineIndex);

    //create pin
    InputPinViews[InInputPinIndex]->CreateWidget(InNodeWidget,ValueLine);

    auto ColorPickBacground= NewWidget<RRectangleWidget>(ValueLine);
    RRectangleWidgetWeakPtr WeakColorPickBacground=ColorPickBacground;
    ColorPickBacground->Anchor.VerticalFill(ValueLine);
    ColorPickBacground->Anchor.LeftReference=ValueLine;
    ColorPickBacground->Anchor.LeftReferenceEdge=EHorizontalWidgetEdge::Center;
    ColorPickBacground->Anchor.RightReference=ValueLine;
    ColorPickBacground->Anchor.RightOffset=BaseViewModel->LineHorizontalPadding;

    ColorPickBacground->Radius=BaseViewModel->BackgroundRadius;
    ColorPickBacground->FillColor= [this,WeakColorPickBacground,InInputPinIndex](){
        SVec4 Value=InputPinViews[InInputPinIndex]->GetDefaultXYZW();
        return SColor(Value.X,Value.Y,Value.Z,Value.W);
    };
    ColorPickBacground->Visible=[this,InInputPinIndex](){
        return !InputPinViews[InInputPinIndex]->HasValidLink();
    };

    auto PinNameWidget=NewWidget<RTextWidget>(ValueLine);
    PinNameWidget->VerticalAlignment=ETextVerticalAlignment::Center;
    PinNameWidget->Anchor.VerticalFill(ValueLine);
    PinNameWidget->Anchor.RightReference=ValueLine;
    PinNameWidget->Anchor.RightOffset=BaseViewModel->LineHorizontalPadding;
    PinNameWidget->Anchor.LeftReference=ValueLine;
    PinNameWidget->Anchor.LeftOffset=BaseViewModel->LineHorizontalPadding;
    PinNameWidget->Text=[this,InInputPinIndex](){
        return BaseViewModel->GetInputPinName(InInputPinIndex);
    };
    

    return ValueLine;
}

TSharedObjectPtr<RWidget> RMaterialGraphNodeView::CreateCheckBoxWidget(
    TSharedObjectPtr<RWidget> InNodeWidget
    , TSharedObjectPtr<RWidget> InParentWidget
    ,int64_t InLineIndex
    ,TDelegate<bool> InCheckState
    ,TWidgetAttribute<CString> InText
    ,TDelegate<void,bool> InOnCheckStatedChanged
    )
{
    auto Line=CreateLine(InNodeWidget,InParentWidget,InLineIndex);

    auto CheckBox=NewWidget<REditorCheckBoxWidget>(Line);
    CheckBox->X=BaseViewModel->LineHorizontalPadding;
    CheckBox->Anchor.VerticalCenterReference=Line;
    CheckBox->Width= BaseViewModel->LineHeight;
    CheckBox->Height= BaseViewModel->LineHeight;
    CheckBox->CheckState=[this,InCheckState]() mutable
    {
        auto bChecked=InCheckState.Execute();
        return bChecked?ECheckBoxWidgetState::Checked:ECheckBoxWidgetState::Unchecked;
    };
    CheckBox->OnCheckStateChanged.Bind([this,InOnCheckStatedChanged](ECheckBoxWidgetState State){
        InOnCheckStatedChanged.ExecuteIfBound(State==ECheckBoxWidgetState::Checked);
    });

    auto Text=NewWidget<RTextWidget>(Line);
    Text->Text=InText.Get();
    Text->Anchor.VerticalFill(Line);
    Text->Anchor.LeftReference=CheckBox;
    Text->Anchor.LeftReferenceEdge=EHorizontalWidgetEdge::Right;
    Text->Anchor.LeftOffset=5;
    Text->VerticalAlignment=ETextVerticalAlignment::Center;

    return Line;
}
